/**
 * ComponentGeneratorService.java
 *
 * Copyright (c) 2009 prjmanager All Rights Reserved.
 *
 * This source file may not be copied, modified or redistributed,
 * in whole or in part, in any form or for any reason, without the express
 * written consent of prjmanager .
 **/
package ro.prjmanager.service;


import ro.prj.manager.Util;
import ro.prj.manager.svn.PrjSvnManager;
import ro.prj.manager.svn.SVNSecure;
import ro.prjmanager.constants.BackendConstants;
import ro.prjmanager.core.service.AbstractService;
import ro.prjmanager.dao.*;
import ro.prjmanager.database.model.Table;
import ro.prjmanager.helpers.ModelsTablesHelper;
import ro.prjmanager.model.*;
import ro.prjmanager.template.TemplateReader;
import ro.prjmanager.template.form.Form;
import ro.prjmanager.core.usr.UserSession;
import ro.prjmanager.velocity.GeneratorContext;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * This class is business logic for component_generator table
 * It manages all transaction maded to component_generator table
 * @author Viorel Tacliciu
 * @version 0.0.1
 **/


public class ComponentGeneratorService  extends AbstractService<CustomComponents,Integer> implements CompGeneratorServiceInterface {
    public static final int MODEL=1;
    public static final int DAO=2;
    public static final int SERVICE=3;
    public static final int ACTION=4;
    public static final int FORM=5;
    public static final int GUI=6;
    public static final int MENU=7;
    public static final int CFG_DAO=8;
    public static final int CFG_SERVICE=9;




    private UsersDao usersDao;
    private HistoryGenerateDao historyGenerateDao;
    private CustomComponentsDao customComponentsDao;
    private ModelsDao modelsDao;
    private ComponentDetailsDao componentDetailsDao;
    private GenericComponentsDao genericComponentsDao;
    private GroupsDao groupsDao;

    




    public UsersDao getUsersDao() {
        return usersDao;
    }

    

    public void setUsersDao(UsersDao usersDao) {
        this.usersDao = usersDao;
    }

    public HistoryGenerateDao getHistoryGenerateDao() {
        return historyGenerateDao;
    }

    public void setHistoryGenerateDao(HistoryGenerateDao historyGenerateDao) {
        this.historyGenerateDao = historyGenerateDao;
    }

    public void create(CustomComponents user){
        getDao().create(user);
    }

    public ModelsDao getModelsDao() {
        return modelsDao;
    }

    public void setModelsDao(ModelsDao modelsDao) {
        this.modelsDao = modelsDao;
    }

    public CustomComponentsDao getCustomComponentsDao() {
        return customComponentsDao;
    }

    public void setCustomComponentsDao(CustomComponentsDao customComponentsDao) {
        this.customComponentsDao = customComponentsDao;
    }

    public ComponentDetailsDao getComponentDetailsDao() {
        return componentDetailsDao;
    }

    public void setComponentDetailsDao(ComponentDetailsDao componentDetailsDao) {
        this.componentDetailsDao = componentDetailsDao;
    }

    public GenericComponentsDao getGenericComponentsDao() {
        return genericComponentsDao;
    }

    public void setGenericComponentsDao(GenericComponentsDao genericComponentsDao) {
        this.genericComponentsDao = genericComponentsDao;
    }

    public GroupsDao getGroupsDao() {
        return groupsDao;
    }

    public void setGroupsDao(GroupsDao groupsDao) {
        this.groupsDao = groupsDao;
    }

    public void delete(Integer id){
        CustomComponents user =new CustomComponents();
        user.setId(id);
        getDao().delete(user);
    }

    public CustomComponents load(Integer id){
         return getDao().find(id,false);
    }

    public List<CustomComponents> listPag(int startPage, int resPerPage) {
        return null;
    }

    public List<CustomComponents> listPag(int startPage, int resPerPage, String orderCol, boolean asc, Object... otherItems) {
        return getDao().listPag(startPage, resPerPage,orderCol, asc, otherItems);
    }

    public List<CustomComponents> list() {
        return getDao().findAll();
    }

    public List<CustomComponents> listPagFilter(int startPage, int resPerPage, String filter) {
        return null;
    }

    public int no(String filter) {
        return getDao().no(filter);
    }

    public void update(CustomComponents entity) {
        getDao().update(entity);
    }


    public void generate(Integer id, UserSession userSession,String comments) {
        CustomComponents componentGenerator=getDao().find(id,false);
        GenericComponents component= componentGenerator.getFkComponents();

        Layers layer=component.getFkProjectLayer().getFkLayer();

        Projects project=component.getFkProjectLayer().getFkProject();

        Template template=component.getFkTemplate();

        Models model=componentGenerator.getFkModel();


        Table table = ModelsTablesHelper.cast(model,modelsDao);

        Models search=new Models();
        search.setClassExtend(model.getJavaName());
        List<Models> modelses=modelsDao.find(search);
        table.setExtended(modelses!=null&&!modelses.isEmpty());
        table.setOracle(((DataBases)getDao().getUserSession().getDataBases()).getFkDbType().getName().equalsIgnoreCase("oracle"));
        Svn svn=(Svn)userSession.getSvn();
        Integer version=1;
        if(componentGenerator.getFkCompGenHistoryGenerate()!=null)
            version=componentGenerator.getFkCompGenHistoryGenerate().size()+1;

        List<CustomComponents> componentGeneratorList= componentGenerator.getFkModel().getFkModelComponentGenerator();

        String modelPack="";
        String servicePack="";
        String daoPack="";
        String actionPack="";

        String modelSuffix="";
        String serviceSuffix="";
        String daoSuffix="";
        String actionSuffix="";
        String repl="" ;



        for(CustomComponents componentGenerator1:componentGeneratorList){
            int fixedComp=componentGenerator1.getFkComponents().getFkFixedComponents().getId();
            String reffComp=componentGenerator1.getFkComponents().getRelativePackage();
            String reffSuffix=componentGenerator1.getFkComponents().getSuffix();

            if(fixedComp==MODEL){
                modelPack=reffComp;
                if(reffSuffix!=null)
                modelSuffix=reffSuffix;
            }else if(fixedComp==DAO){
                daoPack=reffComp;
                if(reffSuffix!=null)
                daoSuffix=reffSuffix;
            }else if(fixedComp==SERVICE){
                servicePack=reffComp;
                if(reffSuffix!=null)
                serviceSuffix=reffSuffix;
            }else if(fixedComp==ACTION){
                actionPack=reffComp;
                if(reffSuffix!=null)
                actionSuffix=reffSuffix;
            }else if(fixedComp==MENU){
                if(componentGenerator1!=null&&componentGenerator1.getComponentDetails()!=null)
                    repl=componentGenerator1.getComponentDetails().getGuiMenuPreffix();

            }else if(fixedComp==CFG_DAO){

            }else if(fixedComp==CFG_SERVICE){

            }

        }
        String fileOutputPath=getGeneratedFilePath(layer, project, componentGenerator, table,template.getFileGenName());
        if(template.isNeedUpdate()){
            appendToFile(project, layer, componentGenerator, table, template,(Users)userSession.getUser(),
                    svn,version,modelPack,modelSuffix,daoPack,daoSuffix,servicePack,serviceSuffix,actionPack,actionSuffix,
                    template.getReplacer().replace("$content$",repl),fileOutputPath);
        }
        else
            generateClassFile(project, layer, componentGenerator, table, template,(Users)userSession.getUser(),
                    svn,version,modelPack,modelSuffix,daoPack,daoSuffix,servicePack,serviceSuffix,actionPack,
                    actionSuffix,fileOutputPath);

        HistoryGenerate historyGenerate=new HistoryGenerate();
        historyGenerate.setComments(comments);
        historyGenerate.setFkCompGen(componentGenerator);

        Users usrPers=usersDao.find(((Users)userSession.getUser()).getId(),false);
        historyGenerate.setFkUser(usrPers);
        historyGenerate.setDate(new Date());
        historyGenerate.setLatest(1);

        if(componentGenerator.getFkCompGenHistoryGenerate()==null)
            componentGenerator.setFkCompGenHistoryGenerate(new ArrayList<HistoryGenerate>());
        else{
            if(!componentGenerator.getFkCompGenHistoryGenerate().isEmpty())
                for(int p=0;p<componentGenerator.getFkCompGenHistoryGenerate().size();p++){
                    componentGenerator.getFkCompGenHistoryGenerate().get(p).setLatest(0);
                }
        }

//        getHistoryGenerateDao().create(historyGenerate);

        componentGenerator.getFkCompGenHistoryGenerate().add(historyGenerate);
//        getDao().persist(componentGenerator);


    }

    public void generate(Groups groups, UserSession userSession, String comments) {
        List<CustomComponents> customComponentses=customComponentsDao.list(groups);
        if(customComponentses!=null&&!customComponentses.isEmpty())
        for(CustomComponents customComponents:customComponentses){
            generate(customComponents.getId(),userSession, comments);
        }
         
    }

    public void generate(List<Integer> selectedModelIds, List<Integer> selectedGenericComponents, Integer selectedComponentsDetail) {
        String comments="Massive generation";
        //try to find custom components if not than create a new one and then create group to associate generic components
        if(selectedModelIds==null||selectedModelIds.isEmpty()
                ||selectedGenericComponents==null||selectedGenericComponents.isEmpty()||
                selectedComponentsDetail==null)
            throw new RuntimeException("Nu sunt completate toate campurile");

        for(Integer idModel:selectedModelIds){
            Groups group=null;
            for(Integer idGenericComp:selectedGenericComponents){
                 CustomComponents customComponents=customComponentsDao.findByIds(
                         idModel,idGenericComp, selectedComponentsDetail
                 );
                 if(customComponents==null){
                     //try to see if there is one custom not null per associated group components
                     Models models=modelsDao.find(idModel,false);
                     ComponentDetails componentDetails=componentDetailsDao.find(selectedComponentsDetail,false);
                     GenericComponents genericComponents=genericComponentsDao.find(idGenericComp,false);
                     List<CustomComponents> customComponentses= models.getFkModelComponentGenerator();
                     //if customComponentses is not null then we create one new and associate with these
                     if(customComponentses!=null&&!customComponentses.isEmpty()){
                         CustomComponents customComp=customComponentses.get(0);
                         CustomComponents newCustom=new CustomComponents();
                         newCustom.setComponentDetails(componentDetails);
                         newCustom.setFkComponents(genericComponents);
                         newCustom.setFkModel(models);
                         newCustom.setFkGroups(customComp.getFkGroups());
                         newCustom.setName(models.getJavaName()+"-"+genericComponents.getName());
                         models.getFkModelComponentGenerator().add(newCustom);
                         customComponentsDao.create(newCustom);
                         generate(newCustom.getId(),getDao().getUserSession(), comments);
                     }else{
                         //create new group
                         Groups grp=new Groups();
                         Projects project=genericComponents.getFkProjectLayer().getFkProject();
                         grp.setFkProject(project);
                         grp.setName(models.getJavaName()+"-groups");
                         grp.setDescription("Grupare componente "+models.getJavaName());
                         groupsDao.create(grp);

                         CustomComponents newCustom=new CustomComponents();
                         newCustom.setComponentDetails(componentDetails);
                         newCustom.setFkComponents(genericComponents);
                         newCustom.setFkModel(models);
                         newCustom.setFkGroups(grp);
                         newCustom.setName(models.getJavaName()+"-"+genericComponents.getName());
                         models.setFkModelComponentGenerator(new ArrayList<CustomComponents>());
                         models.getFkModelComponentGenerator().add(newCustom);
                         customComponentsDao.create(newCustom);
                         generate(newCustom.getId(),getDao().getUserSession(), comments);
                     }
                 }else{
                    //just call generate method
                      generate(customComponents.getId(),getDao().getUserSession(), comments);
                 }
            }


        }
    }

    private void generateClassFile(Projects project,Layers layer, CustomComponents component,Table table,
                                    Template template,Users user,Svn svn,int version,
                                    String modelPack,String modelSuffix,
                                    String daoPack,String daoSuffix,
                                    String servicePack,String serviceSuffix,
                                    String actionPack,String actionSuffix,String fileOutputPath){

        try {
            Form form=new Form(layer, component, table, project, user, version, modelPack,modelSuffix,
                    daoPack,daoSuffix,servicePack,serviceSuffix,actionPack,actionSuffix);

            GeneratorContext context = new GeneratorContext(form);

            byte b[]=TemplateReader.evaluate(context, "File" + fileOutputPath,template.getVmFile());


            SVNSecure svnSecure=new SVNSecure();
            svnSecure.setUrl(svn.getUrl());
            svnSecure.setPassword(svn.getPassword());
            svnSecure.setName(svn.getUserName());
            svnSecure.setDir(svn.getName());

            PrjSvnManager prjSvnManager= PrjSvnManager.instance(svnSecure);

            String dirPath=fileOutputPath.substring(0,fileOutputPath.lastIndexOf("/"));
            String fileName=fileOutputPath.substring(fileOutputPath.lastIndexOf("/"),fileOutputPath.length());

            prjSvnManager.doSvnFile(dirPath,fileName,b);




        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void appendToFile(Projects project,Layers layer, CustomComponents component,Table table,
                                    Template template,Users user,Svn svn,int version,
                                    String modelPack,String modelSuffix,
                                    String daoPack,String daoSuffix,
                                    String servicePack,String serviceSuffix,
                                    String actionPack,String actionSuffix,String replacer,String fileOutputPath){

        try {
            Form form=new Form(layer, component, table, project, user, version, modelPack,modelSuffix,
                    daoPack,daoSuffix,servicePack,serviceSuffix,actionPack,actionSuffix);
            GeneratorContext context = new GeneratorContext(form);
            byte b[]=TemplateReader.evaluate(context, "File" + fileOutputPath.replace("//","/"),template.getVmFile());
            SVNSecure svnSecure=new SVNSecure();
            svnSecure.setUrl(svn.getUrl());
            svnSecure.setPassword(svn.getPassword());
            svnSecure.setName(svn.getUserName());
            svnSecure.setDir(svn.getName());
            PrjSvnManager prjSvnManager= PrjSvnManager.instance(svnSecure);
            fileOutputPath=fileOutputPath.replace("//","/");
            String dirPath=fileOutputPath.substring(0,fileOutputPath.lastIndexOf("/"));
            String fileName=fileOutputPath.substring(fileOutputPath.lastIndexOf("/"),fileOutputPath.length());
            ByteArrayOutputStream baos=prjSvnManager.readFile(fileOutputPath);
            byte[] b1=baos.toByteArray();
            byte[] merged= Util.append(b1,b,replacer);
            prjSvnManager.doSvnFile(dirPath,fileName,merged);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


     private String getGeneratedFilePath(Layers layer,Projects project, CustomComponents component,Table table,String fileName){
        StringBuilder sb=new StringBuilder();
        sb.append(BackendConstants.PATH_SEPARATOR);
        sb.append(layer.getName());
        sb.append(BackendConstants.PATH_SEPARATOR);
        if(component.getFkComponents().isWeb())
            sb.append(layer.getWeb());
        else if(component.getFkComponents().isRes())
            sb.append(layer.getRes());
        else sb.append(layer.getSrc());
        sb.append( BackendConstants.PATH_SEPARATOR);
        String relativeRootPackage=component.getFkComponents().isWeb()||component.getFkComponents().isRes()?"":project.getPackageBase();
        String relativeRootPath;
        if(relativeRootPackage.indexOf(BackendConstants.PACKAGE_SEPARATOR)>0)
            relativeRootPath=relativeRootPackage.replace(BackendConstants.PACKAGE_SEPARATOR,
                    BackendConstants.PATH_SEPARATOR) ;
        else relativeRootPath=relativeRootPackage;
        sb.append(relativeRootPath);
        sb.append( BackendConstants.PATH_SEPARATOR) ;
        sb.append(component.getFkComponents().getRelativePackage().replace(BackendConstants.PACKAGE_SEPARATOR,BackendConstants.PATH_SEPARATOR));
        sb.append( BackendConstants.PATH_SEPARATOR);
        if(fileName!=null)
            sb.append(fileName);
        else
            if(component.getFkComponents().isWeb())
                sb.append(table.getJavaName().toLowerCase()).append(BackendConstants.PATH_SEPARATOR).append(table.getJavaName().toLowerCase());
            else
                sb.append(table.getJavaName());
        if(component.getFkComponents().getSuffix()!=null)
            sb.append(component.getFkComponents().getSuffix());
        sb.append(".");
        sb.append(component.getFkComponents().getFkTemplate().getFileGenExt());
        return sb.toString();
    }
}
